欸,先說,今天要聊的不是咖啡,也不是人生哲學,雖然兩者都可以讓你凌晨三點抱著鍵盤哭。
今天,我們聊 Alertmanager。
對,就是那個 Prometheus 的好基友,負責告訴你「欸,你的系統正在冒煙🔥」,
還順便幫你分類、抑制、通知——簡直是魔法水晶球。
你知道嗎?告警其實是一種藝術。
太多會變成噪音,太少又會讓你變成隔天早上那個「為什麼服務掛了一整夜」的倒楣蛋。
就像感情關係,對方傳 LINE 不回會被說冷淡,但回太快又被說「你是不是沒事幹?」
Alertmanager 的世界就是這樣的修羅場。
很多人以為告警就只是「紅燈亮 → 人出動」。
錯。
那就像以為愛情只是「在一起 → 結婚」,中間還有一堆 YAML、TLS、SMTP、還有心理創傷。
而我曾經也是這樣。直到有一天凌晨三點,我的 Slack 狂跳:
🔥 Database exploded again
💀 Disk usage 99%
🧯 Memory meltdown initiated
我還沒清醒,就看到手機 47 則通知。
打開 Dashboard,滿滿紅色。
那一刻我懂了,Alertmanager 不是工具,它是報應生成器(karmic retribution as a service)。
所以今天這篇,我想用最誠懇的心情(還有最崩潰的靈魂)來聊聊:
如何讓 Alertmanager 成為你可靠的魔法塔,而不是半夜吵醒你、讓你懷疑人生的詛咒裝置。
先講原理,因為工程師不懂原理就會亂修(我上次改 config 檔結果整個 cluster 沒聲音)。
Alertmanager 的工作只有四個字:
分組、抑制、路由、通知。
看起來簡單吧?
對,就像「交女朋友」看起來也很簡單。
實際上要先學會分組(哪個是工作朋友、哪個是前任)、抑制(不要同時回兩個人訊息)、路由(正確送達訊息)、通知(但不要被已讀不回)。
Alertmanager 會把相似的告警打包成一組,避免你的通知系統像炸裂一樣狂發訊息。
舉例:
假設五個 API 同時 timeout,正常人希望收到一封通知,而不是五封讓你懷疑人生的信。
route:
group_by: ['alertname']
group_wait: 10s
group_interval: 1m
repeat_interval: 3h
group_by 告訴 Alertmanager:這些告警有相同的「姓氏」,可以住同一棟宿舍。
group_wait 像是「我再等 10 秒看看會不會有別的異常進來,一起報吧」。
人生也是這樣,有時候要等一下,看事情會不會更糟。
抑制是 Alertmanager 最像心理醫生的部分。
它會判斷「這個告警是不是因為別的問題引起的?」
例如:NetworkDown 發生時,API timeout、DB error 也接連發生,
但 Alertmanager 很貼心地說:「嗯,既然橋都塌了,別再罵廚師了。」
設定長這樣:
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['instance']
翻譯一下:
如果 critical 告警在同一個 instance 已經存在,那 warning 就閉嘴吧。
有時候我覺得人生也該有這功能。
例如:「如果老闆已經在罵我,Slack bot 就不要再提醒我 deployment failed。」
這是 Alertmanager 的靈魂。
你可以定義誰該收到哪種告警,畢竟「誰該被吵醒」是一門哲學。
route:
receiver: default-team
routes:
- match:
team: ops
receiver: ops-team
- match:
team: app
receiver: app-team
這樣 ops 的告警會寄給 ops-team,app 的告警則給 app-team。
如果你沒設定 match,那所有告警都會寄給 default-team(也就是你自己)。
這點很真實,人生中沒設定界線的人,最後都在收別人留下的坑。
好啦,前面那些邏輯都是為了這一刻——寄信。
有時候是 Email,有時候是 Slack,有時候是 PagerDuty,
而這些通知方式,就是你半夜被吵醒的主因。
receivers:
- name: ops-team
email_configs:
- to: ops@example.com
from: monitor@example.com
smarthost: smtp.gmail.com:587
auth_username: monitor@example.com
auth_password: ${APP_PASSWORD}
require_tls: true
⚠️ 拜託用 Google App Password,不要把密碼硬編在 YAML 裡。
有次我不小心 commit 了 .yml,結果 CI/CD 檢查寄信給我:「你是不是瘋了?」
我那一刻才知道什麼叫自作孽不可活。
group_wait、group_interval 與 repeat_interval。inhibit_rules 與 labels。env_file 或 Secret Manager,避免硬編碼。嗯,好啦,不知道你是不是像我一樣,有時候 debug 抄程式碼比追前女友還累。
如果你把 Prometheus 想成是那個巡邏的騎士,那 Alertmanager 就是他身邊的通報官。
Prometheus 是那個巡邏騎士,發現不對勁就大喊『出事啦!』,然後把鍋交給 Alertmanager 幫你寫成通知信。
Alertmanager 接到消息後,整理成漂亮的信、上好標題、配上 emoji,再寄給你。
Prometheus 設定:
alerting:
alertmanagers:
- static_configs:
- targets:
- 'alertmanager:9093'
rule_files:
- '/etc/prometheus/rules/*.yml'
如果 targets 寫錯?
恭喜,你就擁有一個啞巴警報塔。
敵人都打進內城了,你的塔還在睡覺。😴
以下這段我敢保證,你一定會 copy 貼到 prometheus。
但拜託,先看懂。
groups:
- name: System
rules:
- alert: ServiceDown
expr: up == 0
for: 2m
labels:
severity: page
team: ops
annotations:
summary: 'Instance {{ $labels.instance }} down'
description: '服務掛了兩分鐘,可能是 DB 又炸了。'
expr 是 PromQL 的靈魂。for: 2m 意思是「這件事發生超過兩分鐘才算真的壞」。
就像感情一樣,有時候只是短暫誤會,不該馬上報警。
再看一個:
- alert: HighCPUUsage
expr: (1 - avg by (instance)(irate(node_cpu_seconds_total{mode="idle"}[5m]))) * 100 > 80
for: 3m
labels:
severity: warning
annotations:
summary: 'High CPU Usage Detected'
description: 'CPU 使用率超過 80%,拜託別再跑 SQL join 了。'
是的,每次看到 CPU 飆高,我都懷疑是不是有人在 production 上直接跑 migration。
(這就像看著自己的人生,明知道會爆,還是硬上。)

group_interval 設太短,就像前任還沒講完又傳下一句:焦慮即服務(Anxiety-as-a-Service)。
太長又會錯過真正的災難。
我曾經把 group_interval 設成 10s,結果告警一波波來,像被前任刷存在感。
現在我設 30s,人生變平靜許多。
當老闆在開罵的時候,你的同事就該閉嘴。
同理,當 NetworkDown,其他子服務不要再跳出「連線逾時」。
設定 inhibition rule,其實就是在告訴系統:「現在不是你講話的時候。」
有時候要學會分配。
critical 給 on-call,warning 給團隊群組,info 給自己。
這就像分手後的社交策略:
「重要的事請打電話,不重要的事請留言。」
每一次改設定都要小心。
太多 rules,人生會爆炸;太少,又沒安全感。
改太快會出事,改太慢也會。
我常覺得 Alertmanager 的 YAML 根本是人生劇本:
要懂得 group,要會 silence,要能 route,要懂得通知對的人。
⚠️ 1. Email 不送出
→ SMTP host 錯。
有次我忘了加 :587,結果整晚沒通知。第二天開會,大家看著我:「為什麼沒報警?」
我只能小聲說:「因為我沒設定 port。」
那一刻,我懂了,port 是愛的語言。
🧨 2. 告警太頻繁
→ group_wait 太短。
我以為設越短越即時,結果變成「通知地獄」,Slack 一直跳。
那畫面像極了女友一天傳 70 則訊息問「你在幹嘛」。

🕓 3. 延遲通知
→ Server 時間不同步。
我花兩小時 debug,最後發現 NTP 沒同步。
那感覺就像你以為是愛情出問題,結果只是時區不同。
補一張簡單流程圖
Prometheus Rules → Alertmanager → Receiver (Slack/Email)
Alertmanager 不只是寄信的小幫手,它其實能玩很深。
多環境共用設定
用環境變數控制 SMTP、Receiver,不同環境共用模板。
像是「在 staging 試愛,在 production 結婚」。
分層路由設計
critical → PagerDuty,warning → Slack,info → Dashboard。
分級通知是人類文明的進步。
Cluster 模式
多台 Alertmanager 互相同步狀態,確保你 restart 之後不會忘記前任(啊不是,是告警狀態)。
Template 自訂格式
可以用 Go template 寫出漂亮的訊息,甚至加 emoji。
🚨 [{{ .Status | toUpper }}] {{ .Labels.alertname }}
{{ .Annotations.description }}
我通常會加一個 skull 💀,這樣每次打開 Slack 都覺得自己在玩暗黑破壞神。
老實說,搞懂 Alertmanager 後,我對人際關係都更有耐心了。
因為你會發現,所有錯誤、誤會、崩潰,其實都只是沒設定好「告警規則」。
人生就像監控系統:
有次凌晨 4 點,我被 Slack 叫醒。
打開手機,全是「ServiceDown」。我衝去重啟服務,結果才發現是 DNS 掛了。
那晚我什麼都沒修好,卻開始懂得調整 inhibition rule。
原來穩定,不是沒告警,而是告警剛剛好。
寫這篇的時候是凌晨 2:47。
Slack 還在閃,我的咖啡已經冷掉。
但我心裡有點平靜。
因為我知道,這次的告警會準時來,不會漏,不會吵,
就像一個成熟的關係——穩定、有界線、偶爾冒點火花但不會爆炸。
所以,別再害怕告警。
讓 Alertmanager 成為你的魔法水晶球,
在一堆混亂的 metric 裡告訴你:
「欸,放輕鬆,一切都還沒爆。」
這篇寫完,我發現 Alertmanager 其實不是工具,而是一種哲學。
它提醒我們什麼該回應、什麼該忽略,
就像 debug 自己的人生。
下次當你看到 Slack 跳出「🔥 Database exploded again」,
先別罵,先深呼吸。
想想也許那不是 bug。
那只是宇宙在對你說:「你該睡了,工程師。」💤
明天起床再修,反正世界還沒爆。
global:
scrape_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets:
- "alertmanager:9093"
rule_files:
- "/etc/prometheus/rules/*.yml"
groups:
- name: Service
rules:
- alert: ServiceDown
expr: up == 0
for: 2m
labels:
severity: page
team: app
service: all
annotations:
summary: "Instance {{ $labels.instance }} down"
description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 2 minutes."
- name: System
rules:
- alert: NetworkDown
expr: probe_success == 0
for: 30s
labels:
severity: "critical"
team: ops
service: network
annotations:
summary: "Network unreachable on {{ $labels.instance }}"
description: "Endpoint {{ $labels.instance }} network down for 30s."
- alert: FreeDiskUsage
expr: |
(node_filesystem_avail_bytes{mountpoint="/"} * 100 / node_filesystem_size_bytes{mountpoint="/"}) < 20
or
(node_filesystem_avail_bytes{mountpoint="/var"} * 100 / node_filesystem_size_bytes{mountpoint="/var"}) < 20
for: 5m
labels:
severity: warning
team: ops
service: storage
annotations:
summary: "Low disk space on {{ $labels.instance }}"
description: "Available disk space on {{ $labels.instance }} is below 20%."
- alert: MemoryUsage
## 記憶體使用率%
expr: ((1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100) > 50
for: 2m
labels:
severity: warning
team: ops
service: system
annotations:
summary: " the total percentage of used memory"
description: "{{ $labels.instance }} of job {{ $labels.job }}"
- alert: HighCPUUsage
# CPU 使用率 進行監控,並且當使用率超過 80% 時會https://github.com/hello02923/prometheus發出告警,
expr: (1 - sum by (instance) (irate(node_cpu_seconds_total{job="node_exporter_metrics",mode="idle"}[5m]))) * 100 > 80
for: 2m
labels:
severity: warning
team: ops
service: system
annotations:
summary: "High CPU Usage Detected"
description: "The CPU usage for instance {{ $labels.instance }} has exceeded 80% over the last 5 minutes, indicating a high load on the system."
更多規則可參考 GitHub 範例
小提醒:for: 指定持續多久才觸發告警,別像我第一次設 1s,整個 Slack 被炸到懷疑人生。
告警等級與通知方式
| Severity | 描述 | 通知方式 |
|---|---|---|
| critical / page | 系統或服務不可用,需立即處理 | Pager、電話、SMS |
| warning | 潛在問題或資源使用過高 | Slack / Email |
| info / debug | 資訊性事件,不影響服務 | Dashboard、Email(選用) |